<template>
	<view style="display: flex;justify-content: space-between;flex-direction: column;align-items: center;">
		<view class="" style="width: 700rpx;">

			<view style="background-color: #fff;border-style: dashed;width:100%; ">
				<view style="padding: 10px;text-align: center;background-color: aquamarine;">
					消息模版【<span v-if="list[btn]">{{list[btn].btn}}</span>】
				</view>
				<view style="display: flex;line-height: 3em;align-items: center;">
					<view style="width: 80px;">链接地址：</view>
					<input type="text" style="background-color: #eee; flex: 1;" v-model="wsUrl" />
				</view>
				<view style="width: 100%;display: flex;">
					<view style="width: 80px;">消息体：</view>
					<textarea v-if="list[btn]" style="background-color: #eee; flex: 1;min-height: 200px;width: 100%;" v-model="list[btn].content" placeholder="" />
				</view>

			</view>
			<view style="background-color: aliceblue;border-style: dashed;width:100%; ">
				<view style="padding: 10px;text-align: center;background-color: aquamarine;">
					消息内容切换
				</view>
				<view class="" style="display: flex;justify-content: space-between;">
					<view class="" v-for="(item,k) in list" style="min-width: 100px;">
						<button @click="btn=k" :type="btn==k?'warn':'primary'">{{item.btn}} </button>
					</view>
				</view>
			</view>
			<view style="background-color: aliceblue;border-style: dashed;width:100%; ">
				<view style="padding: 10px;text-align: center;background-color: aquamarine;">
					操作执行
				</view>
				<view class="" style="display: flex;justify-content: space-between;">
					<button @click="cleanCache">清缓存</button>
					<button @click="connect" type="primary"> 1 建立链接 </button>
					<button @click="confirmSend()" type="primary">2 发送消息 </button>
				</view>
			</view>
			<view class="">
				<view class="" v-for="item in msgList">
					{{item}}
				</view>
			</view>
		</view>
	</view>
</template>
<script>
	export default {
		data() {
			return {
				btn: "0",
				list:uni.getStorageSync("msgData")?uni.getStorageSync("msgData"): {"0":{
					 content:uni.getStorageSync("msgData") ? uni.getStorageSync("msgData") : JSON.stringify({
						key: "client_bind",
						timestamp: new Date().getTime(),
						data: {
							"deviceId": "12345dfdsf343",
							"deviceName": "google",
							"language": "zh-CN"
						}
					}),
					act:3,
					btn:"通用"
					},"2":{
					 content: uni.getStorageSync("bindRoom") ? uni.getStorageSync("bindRoom") : JSON.stringify({
						"key": "room_bind",
						"data": {
							"token": "95c459735bdd0e405aaac4388d02b2fc",
							"roomNo": "287"
						}
					}),act:3,btn:"进入房间"}
					,"3":{
					 content: uni.getStorageSync("loginData") ? uni.getStorageSync("loginData") : JSON.stringify({
						key: "client_bind",
						timestamp: new Date().getTime(),
						data: {
							"token": "4842ef27f0fbb51a6129a2b4d56042ba",
							"channel": "web",
							"appVersion": "1.0.0",
							"osVersion": "1.0.1",
							"packageName": "cn.yunque",
							"deviceId": "12345dfdsf343",
							"deviceName": "google",
							"language": "zh-CN"
						}
					}),
					act:3,
					btn:"登录",
					},
				},
				msgList:[],
				msg: '{"token":"95c459735bdd0e405aaac4388d02b2fc","deviceId":"12345dfdsf343"}',
				token: "xxxx",
				title: 'websocket 链接示例',
				wsUrl: uni.getStorageSync("wsUrl") ? uni.getStorageSync("wsUrl") : "ws://127.0.0.1:9001/ws",
				// wsUrl:  "ws://192.168.1.51:9001/ws",
				isRestCon: false,
				socketTask: null,
				/*
				 *特殊的消息类型，999代表被服务端强制下线
				 */
				ACTION_999: "999",
				DATA_HEADER_LENGTH: 1,
				//参考消息类型目前仅用到0,1,2和999 action={2:通讯消息(推送消息),999:强制下线退出登录,3:未定义消息体(推送消息),4:未定义消息体(回复的消息)}
				MESSAGE: 2,
				// 消息类型4
				REPLY_BODY: 4,
				// 消息类型3 登录鉴权
				SENT_BODY: 3,
				// 心跳接受到 马上回复
				PING: 1,
				// 心跳回复给服务的
				PONG: 0,
				PONG_BODY: "",
				ACT: 0,
			}
		},
		watch: {
			btn(i) {
				if (i == 1) {
					this.msg = this.loginData
				} else if (i == 2) {
					this.msg = this.bindRoom
				} else {
					this.msg = this.msgData
				}
			}
		},
		onLoad() {
			// uni.setStorageSync("a",{a:1})
			// var data =uni.getStorageSync("a")
			// console.log(data)

		},
		methods: {
			cleanCache(){
				this.msgList=[]
			},
			// uint8Array 转字符串
			Utf8ArrayToStr(array) {
			  var encodedString = String.fromCharCode.apply(null, array),
				  decodedString = decodeURIComponent(escape(encodedString));
			  return decodedString;
			},
			// 转字符串
			Uint8ArrayToString(fileData) {
				var dataString = "";
				for (var i = 0; i < fileData.length; i++) {
					dataString += String.fromCharCode(fileData[i]);
				}
				return dataString
			},
			// 转uint8数组
			stringToUint8Array(str) {

				var arr = [];
				for (var i = 0, j = str.length; i < j; ++i) {
					arr.push(str.charCodeAt(i));
				}
				var tmpUint8Array = new Uint8Array(arr);
				return tmpUint8Array
			},
			//链接并打开
			connect() {
				uni.setStorageSync("wsUrl", this.wsUrl)
				try {
					if (this.isRestCon || this.socketTask != null) {
						this.socketTask.close()
						return
					}
					this.isRestCon = true
					this.socketTask = uni.connectSocket({
						url: this.wsUrl,
						// protocols:[],
						success: () => {
							this.isRestCon = false
							console.log("正在建立链接");
						},
						fail: (err) => {
							console.log(err)
							this.isRestCon = false
							//重连
							this.connect();
						},
					});
					//打开链接正常
					this.socketTask.onOpen(async (res) => {
						console.log("打开链接成功");
						// 登录鉴权
						// this.bindAccount()
						//监听接收消息
						this.socketTask.onMessage((res) => {

							this.onMessage(res)
							console.log("接受到消息")
						});
					})
					this.socketTask.onError((err) => {
						console.log(err)
						//重连
						this.connect();
					})
					this.socketTask.onClose(() => {
						this.socketTask = null
						this.isRestCon = false
						console.log('onClose');
					})
				} catch (e) {
					console.log(e)
					//重连
					//
					this.connect();
				}
			},

			// 綁定账号
			bindAccount() {

				var data = this.loginData

				this.sendMsg(this.SENT_BODY, data)

			},
			confirmSend(){
				var obj =this.list[this.btn]
				
				if(!obj){
					console.log("消息有误")
					return
				}
				uni.setStorageSync("msgData", this.list)
				var content =obj.content || ""
				var act= obj.act || 1
				this.sendMsg(act,content)
			},
			addMsgList(msg){
				if(msg[1]==0 || msg[1]==1){
					return
				}
				this.msgList.unshift(msg)
			},
			//发送消息
			sendMsg(act,content) {
				var str
				if (typeof content == 'object') {
					str = JSON.stringify(content);
				} else {
					str = content
				}
				this.addMsgList([1,act,str])
				
				const uint8Array = this.stringToUint8Array(str);
				// console.log([act,content,uint8Array])
				var uint8Array2 = new Uint8Array(uint8Array.length + 1);
				uint8Array2[0] = act;
				uint8Array2.set(uint8Array, 1);
				var that = this
				if(this.socketTask){
				this.socketTask.send({
					data: uint8Array2.buffer,
					async success() {
						console.log('消息发送成功')
					},
					async fail() {
						uni.showToast({
							title:"发送失败"
						})
						//重连
						// that.connect();
					}
				})	
				}else{
					uni.showToast({
						title:"socket 未连接"
					})
				}
			},

			// 收到的消息
			onMessage(e) {
				this.PONG = 0
				this.PING = 1
				this.MESSAGE = 2
				this.SENT_BODY = 3
				this.REPLY_BODY = 4
				let msg
				let data = new Uint8Array(e.data);
				//第一个值 是消息类型
				let type = data[0];
				const uint8Array = data.slice(1, data.length);
				// const arrayBuffer = uint8Array.buffer;
				const body = this.Utf8ArrayToStr(uint8Array)
				this.addMsgList([0,type,body])
				// const textDecoder = new TextDecoder();
				// const body = textDecoder.decode(arrayBuffer)
				// console.log([type, body,uint8Array])
				switch (type) {
					case
					this.PING:
						this.pong();
						break
					case this.MESSAGE:
						// 消息
						try {
							msg = body;
						} catch (e) {

						}
						break
					case this.REPLY_BODY:
						console.log(JSON.parse(body))
						// 服务端推过来的消息内容
						msg = body;
						var code = parseInt(msg.code)
						if (msg.key === 'client_bind') {
								uni.showToast({
									title:msg.msg||"收到消息"
								})
							switch (code) {
								case 200:
									console.log('wss握手绑定成功')
									break;
								case 401:
									console.log('wss握手绑定失败')
									break;
								default:
									break;
							}
						}else if (msg.key === 'client_bind') {
							uni.showToast({
								title:msg.msg||"收到消息"
							})
							switch (code) {
								case 200:
									console.log('wss握手绑定成功')
									break;
								case 401:
									console.log('wss握手绑定失败')
									break;
								default:
									break;
							}
						}
						break
					default:
						break
				}
			},
			//手动关闭链接
			close() {
				this.socketTask.close({
					success(res) {
						console.log("手动关闭成功")
					},
					fail(err) {}
				})
			},
			pong() {
				this.sendMsg(this.PONG, "PONG")
			}

		}
	}
</script>
<style>

</style>